var bd = WebApplication.CreateBuilder(args);

// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
bd.Services.AddEndpointsApiExplorer();
bd.Services.AddSwaggerGen();
bd.Services.AddCors(options => {
    options.AddPolicy(name: "PolicyAAA",
                      b => {
// allow everything (origins, methods, and headers)
                          b.AllowAnyOrigin()
                              .AllowAnyMethod()
                              .AllowAnyHeader();
                      });
});

var app = bd.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment()){
    app.UseSwagger();
    app.UseSwaggerUI();
}

// Enable CORS with the defined policy
app.UseCors("PolicyAAA");

app.UseDefaultFiles();app.UseStaticFiles();
// --------------------------------------------------
// 0 the commandline arguments 🐢
string
    o01_backGrpc = "",          // usually localhost:50051, s
    o02_archiveFolder = "/home/me/repo/work/n3c/",
    o03_listeningAddress = "http://0.0.0.0:5024",
    o06_mockInfos = "/home/me/repo/work/n3c/front3/src/c02-posts.tmp.json", // mock infos, used in mock stage I
    o07_mockT = "/home/me/repo/work/n3c/bk/T.json"; // mock T, used in mock stage I

int
    o10_nSlot = 1; // number of workers, default 1

bool
    o04_mockRest = false, // 1: mock rest, 2: mock grpc, 3: real grpc
    o05_debug = false, // debug mode, print all requests
    o08_mockF2 = false, // flag to mock F2
    o09_mockF4 = false; // flag to mock F4


/*
  --back-grpc=localhost:50051
  --archive-folder=/home/me/repo/work/n3c/
  --listening-address=http://0.0.0.0:5025
  --mock-rest

  run:
  dotnet run -- --archive-folder=/home/me/repo/work/n3c/ --listening-address=http://0.0.0.0:5025
  dotnet run -- --mock-rest \
           --archive-folder=/home/me/repo/work/n3c/ --listening-address=http://0.0.0.0:5024 \
           --mock-infos=/home/me/repo/work/n3c/front3/src/c02-posts.tmp.json \
           --mock-t=/home/me/repo/work/n3c/bk/T.json

  dotnet run -- --mock-rest \
           --listening-address=http://0.0.0.0:5024                               \
           --mock-infos=/home/me/repo/work/n3c/front3/src/c02-posts.tmp.json \
           --mock-t=/home/me/repo/work/n3c/bk/T.json
*/

for (int i = 0; i < args.Length; i++) {
    o01_backGrpc = f(args[i], "back-grpc") ?? o01_backGrpc;
    o02_archiveFolder = f(args[i], "archive-folder") ?? o02_archiveFolder;
    o03_listeningAddress = f(args[i], "listening-address") ?? o03_listeningAddress;
    o04_mockRest = f_bool(args[i], "mock-rest") ?? o04_mockRest;
    o06_mockInfos = f(args[i], "mock-infos") ?? o06_mockInfos;
    o07_mockT = f(args[i], "mock-t") ?? o07_mockT;
    o08_mockF2 = f_bool(args[i], "mock-f2") ?? o08_mockF2;
    o09_mockF4 = f_bool(args[i], "mock-f4") ?? o09_mockF4;
    o10_nSlot = f_int(args[i], "n-parallel") ?? o10_nSlot;

}

I07RESTServable? a = null;
if (o04_mockRest){
    // --------------------------------------------------
    // Mock Stage I: mock the whole backend
    S.LogInfo($"🦜: Mock server started: version 25.08.13");
    a = new I07RESTServable.Mock(p:o06_mockInfos, p0:o07_mockT);
}else{
    // --------------------------------------------------
    // Mock Stage II: mock the grpc server
    // 0. the `running` token:
    CancellationTokenSource s = new CancellationTokenSource();
    // 1. the crew
    // 1.1 the archiver 🐝
    JsonlArchiver i4 = new JsonlArchiver(p1:o02_archiveFolder);
    // 1.1b 🦜 : let it study the archive folder before we start
    TChain.Cid = await i4.study();

    // 1.2 the ToDoPoolMgr 🦋
    ToDoPoolMgr pm = new ToDoPoolMgr{c0 = s.Token};
    // 1.3 the mocked grpc server 🐹
    I01Backable? i1;
    if (o01_backGrpc == "") {
        S.LogInfo($"🦜: using mocked grpc server, stage");
        i1 = new I01Backable.Mock();
    }else{                      // real grpc server
        SemiPatchedGrpcLiason.M o = SemiPatchedGrpcLiason.M.None;
        if (o08_mockF2) o |= SemiPatchedGrpcLiason.M.F2; // mock F2
        if (o09_mockF4) o |= SemiPatchedGrpcLiason.M.F4; // mock F4
        S.LogInfo($"🦜: using patched grpc server at {S.CYAN}{o01_backGrpc}{S.NOR} with option: with option:{S.BLUE}0x{(byte)o:X2}{S.NOR}");
        i1 = new SemiPatchedGrpcLiason(o01_backGrpc, o);
    }
    // 1.4 the queue manager 🐦
    ToExeQueueMgr qm = new ToExeQueueMgr{
        c0 = s.Token, i1 = i1, i2 = pm as I02Poolable , i4 = i4
    };
    // 1.5 the rpc
    a = new RestMgr{i5 = pm as I05ForRESTPoolAccessible, i6 = qm as I06ForRESTChainInfoGettable,
        i8 = i4 as I08ForRESTChainGettable
    };
    // 2. start the pm and qm
    pm.Start(qm as I03Queueable);
    qm.Start(Nt: o10_nSlot);

}
// --------------------------------------------------
app.MapGet("/api/R00_ping",a.R00_ping);
// app.MapPost("/api/R01_newTestProject", a.R01_newTestProject);
// app.MapPost("/api/R01_newTestProject", DebugF);
app.MapGet("/api/R02_getRChainInfos", a.R02_getRChainInfos);
app.MapGet("/api/R03_pauseChain", a.R03_pauseChain);
app.MapGet("/api/R04_resumeChain", a.R04_resumeChain);
app.MapGet("/api/R05_getChainById", a.R05_getChainById);
app.MapPost("/api/R06_postChain", a.R06_postChain);
app.UseExceptionHandler(N.h);

app.Run(o03_listeningAddress);

async Task<W<string>> DebugF(HttpRequest r){
    S.LogInfo($"R01_newTestProject called, url: {S.GREEN}{r.Path}{S.NOR}");
    
    // Print request method and path
    S.LogInfo($"Method: {r.Method}");
    S.LogInfo($"Path: {r.Path}");
    S.LogInfo($"QueryString: {r.QueryString}");
    
    // Print headers
    S.LogInfo("Headers:");
    foreach (var header in r.Headers){
        S.LogInfo($"  {header.Key}: {string.Join(", ", header.Value.ToArray())}");
    }
    
    // Print request body
    r.EnableBuffering(); // Allow multiple reads of the body
    using var reader = new StreamReader(r.Body, System.Text.Encoding.UTF8, leaveOpen: true);
    var body = await reader.ReadToEndAsync();
    r.Body.Position = 0; // Reset position for potential later reads
    S.LogInfo($"Body: {body}");
    
    // Print content type and length
    S.LogInfo($"Content-Type: {r.ContentType}");
    S.LogInfo($"Content-Length: {r.ContentLength}");
    
    // Print additional request info
    S.LogInfo($"Protocol: {r.Protocol}");
    S.LogInfo($"Scheme: {r.Scheme}");
    S.LogInfo($"Host: {r.Host}");
    
    return N.OK();
   
}

string? f(string o, string s="back-grpc") {
    if (o.StartsWith("--" + s + "=")) {
        string i =  o.Substring(s.Length + 3);
        S.LogInfo($"🦜: parsed option {S.BLUE}{s}{S.NOR} in {S.RED}{o}{S.NOR}, got value {S.CYAN}{i}{S.NOR}");
        return i;
    }
    return null;
}

int? f_int(string o, string s="mock-stage") {
    string r = f(o, s);
    if (r != null){
        S.LogInfo($"🦜: parsed option {S.BLUE}{s}{S.NOR} in {S.RED}{o}{S.NOR}, got value {S.CYAN}{r}{S.NOR}");
    }
    return (r == null) ? null : int.Parse(r); // let it throw if not parsable
}

bool? f_bool(string o, string s="debug") {
    s = "--" + s;
    if (!o.StartsWith(s)) return null; // not the option we are looking for
    bool ok =  o == s || o == s + "=true" || o == s + "=1";
    S.LogInfo($"🦜: parsing option >{S.BLUE}{s}{S.NOR}< in >{S.RED}{o}{S.NOR}< got {S.CYAN}{ok}{S.NOR}");
    return ok;
}
